﻿using ArtMath.Attribute;
using ArtMath.Component.Point;
using ArtMath.Converter;
using ArtMath.Core.Data;
using ArtMath.Core.Helper;
using ArtMath.Data;
using ArtMath.Helper;
using ArtMath.PointCollection;
using ArtMath.Resource;
using ArtMath.Setting;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using ArtMath.CommonType;

namespace ArtMath.Component.ConicalSection
{
    /// <summary>
    /// 椭圆基类
    /// </summary>
    [Serializable]
    public abstract class EllipseBase : ClosedShapeBase, IConic
    {
        public static readonly double[] TofEllipse = new double[]
        {4, 3.96148349477490, 3.92533250962187, 3.89117422292298, 3.85879164718016, 3.82802439918663, 3.79874361647867,
            3.77084105866915, 3.74422326537321, 3.71880801327783, 3.69452198190990, 3.67129912086701, 3.64907945472479,
            3.62780817666855, 3.60743494120982, 3.58791329922395, 3.56920023782930, 3.55125579948155, 3.53404276223164,
            3.51752636810292, 3.50167408994817, 3.48645542952263, 3.47184174120370, 3.45780607702010, 3.44432304956611,
            3.43136871006273, 3.41892043935192, 3.40695685001466, 3.39545769812121, 3.38440380337240, 3.37377697659147,
            3.36355995368760, 3.35373633534412, 3.34429053179212, 3.33520771211943, 3.32647375763950, 3.31807521890635,
            3.30999927601475, 3.30223370186867, 3.29476682813938, 3.28758751366641, 3.28068511508303, 3.27404945947154,
            3.26767081887469, 3.26153988650789, 3.25564775453253, 3.24998589326492, 3.24454613170739, 3.23932063929922,
            3.23430190879450, 3.22948274018256, 3.22485622557421, 3.22041573498402, 3.21615490294455, 3.21206761589424,
            3.20814800028541, 3.20439041136326, 3.20078942257070, 3.19733981553750, 3.19403657061554, 3.19087485792477,
            3.18785002887734, 3.18495760814971, 3.18219328607485, 3.17955291142852, 3.17703248458589, 3.17462815102586,
            3.17233619516265, 3.17015303448521, 3.16807521398648, 3.16609940086584, 3.16422237948909, 3.16244104659134,
            3.16075240670929, 3.15915356782996, 3.15764173724421, 3.15621421759367, 3.15486840310070, 3.15360177597158,
            3.15241190296374, 3.15129643210828, 3.15025308957981, 3.14927967670591, 3.14837406710897, 3.14753420397376,
            3.14675809743431, 3.14604382207416, 3.14538951453420, 3.14479337122298, 3.14425364612429, 3.14376864869728,
            3.14333674186481, 3.14295634008557, 3.14262590750607, 3.14234395618881, 3.14210904441281, 3.14191977504339,
            3.14177479396777, 3.14167278859356, 3.14161248640722, Math.PI};
        double step;
        //protected double focusAngle;
        //protected PointD center, Pcenter;
        protected Ellipse ske = new Ellipse() { Curves = new LengthCurve[] { new LengthCurve() { IsClosed = true } } },
            pske = new Ellipse() { Curves = new Curve[] { new Curve() { IsClosed = true } } };
        protected LengthCurve newCur = new LengthCurve() { IsClosed = true };
        protected Curve newPCur = new Curve() { IsClosed = true };
        List<PointF[]> track = new List<PointF[]>();
        PadStringX prec;
        PropertyDisplayer cDisplayer, aDisplayer, bDisplayer, fp1Displayer, fp2Displayer, eDisplayer, ctDisplayer, pDisplayer;
        public EllipseBase(SketchPad pad, string name, ToolTypeName toolType, bool addToList = true) : base(pad, name, toolType, addToList)
        {
            Accuracy = new PadStringX(Pad, Settings.Instance.EllipseAccuracy);
            step = 1 / Settings.Instance.EllipseAccuracy;
            FocalHalfLengthDisplayer = new PropertyDisplayer(this, "FocalHalfLength");
            LongAxisHalfLengthDisplayer = new PropertyDisplayer(this, "LongAxisHalfLength");
            ShortAxisHalfLengthDisplayer = new PropertyDisplayer(this, "ShortAxisHalfLength");
            FocusPoint1Displayer = new PropertyDisplayer(this, "Focus1") { OffSet = AnchorOffset };
            FocusPoint2Displayer = new PropertyDisplayer(this, "Focus2") { OffSet = AnchorOffset };
            EccentricityDisplayer = new PropertyDisplayer(this, "Eccentricity");
            CenterDisplayer = new PropertyDisplayer(this, "Center");
            FocusDirectrixDistanceDisplayer = new PropertyDisplayer(this, "FocusDirectrixDistance");
        }
        public override PointD MassPoint
        {
            get { return Center; }
        }
        public override PointCollectionsManager Skeleton
        {
            get
            {
                return new PointCollectionsManager(ske);
            }
        }
        public override PointCollectionsManager PSkeleton
        {
            get
            {
                return new PointCollectionsManager(pske);
            }
        }
        public override PointCollectionsManager NewSkeleton
        {
            get
            {
                build(newCur, null, NewLongAxisHalfLength, NewShortAxisHalfLength, NewFocusAngle, NewCenter);
                return new PointCollectionsManager(new Ellipse(NewCenter, NewFocusAngle, NewLongAxisHalfLength, NewShortAxisHalfLength) { Curves = new LengthCurve[] { newCur } });
            }
        }
        public override PointCollectionsManager NewPSkeleton
        {
            get
            {
                build(null, newPCur, NewLongAxisHalfLength, NewShortAxisHalfLength, NewFocusAngle, NewCenter);
                return new PointCollectionsManager(new Ellipse() { Center = NewPCenter, Curves = new Curve[] { newPCur } });
            }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("LongAxisHalfLength"), ReadOnly(true)]
        public double LongAxisHalfLength
        {
            get { return ske.LongAxisHalfLength; }
            protected set
            {
                ske.LongAxisHalfLength = value;
                Pad.Canvas.Invalidate();
            }
        }
        [Browsable(false)]
        public virtual double NewLongAxisHalfLength
        {
            get { return LongAxisHalfLength; }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("ShortAxisHalfLength"), ReadOnly(true)]
        public double ShortAxisHalfLength
        {
            get { return ske.ShortAxisHalfLength; }
            protected set
            {
                ske.ShortAxisHalfLength = value;
                Pad.Canvas.Invalidate();
            }
        }
        [Browsable(false)]
        public virtual double NewShortAxisHalfLength
        {
            get { return ShortAxisHalfLength; }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("FocalHalfLength")]
        public virtual double FocalHalfLength
        {
            get { return Math.Sqrt(LongAxisHalfLength * LongAxisHalfLength - ShortAxisHalfLength * ShortAxisHalfLength); }
        }
        [Browsable(false)]
        public virtual double NewFocalHalfLength
        {
            get { return Math.Sqrt(NewLongAxisHalfLength * NewLongAxisHalfLength - NewShortAxisHalfLength * NewShortAxisHalfLength); }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("Eccentricity")]
        public double Eccentricity
        {
            get { return FocalHalfLength / LongAxisHalfLength; }
        }
        [Browsable(false)]
        public double NewEccentricity
        {
            get { return NewFocalHalfLength / NewLongAxisHalfLength; }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("{0}1", "Focus"), TypeConverter(typeof(IntelliPointConverter))]
        public virtual PointD Focus1
        {
            get { return Center.Offset(FocusAngle + Math.PI, FocalHalfLength); }
        }
        [Browsable(false)]
        public virtual PointD NewFocus1
        {
            get { return NewCenter.Offset(NewFocusAngle + Math.PI, NewFocalHalfLength); }
        }
        [Browsable(false)]
        public virtual PointD PFocus1
        {
            get { return Pad.XYToPxy(Focus1); }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("{0}2", "Focus"), TypeConverter(typeof(IntelliPointConverter))]
        public virtual PointD Focus2
        {
            get { return Center.Offset(FocusAngle, FocalHalfLength); }
        }
        [Browsable(false)]
        public virtual PointD NewFocus2
        {
            get { return NewCenter.Offset(NewFocusAngle, NewFocalHalfLength); }
        }
        [Browsable(false)]
        public virtual PointD PFocus2
        {
            get { return Pad.XYToPxy(Focus2); }
        }
        [MultilingualCategory("Structure"), DefaultValue(typeof(PadStringX), "50"), MultilingualDisplayName("Accuracy")]
        public PadStringX Accuracy
        {
            get { return prec; }
            set
            {
                if (prec is object)
                {
                    prec.ParametersValueChanged -= Accuracy_ParametersValueChanged;
                    prec.ExpressionSet -= Accuracy_ExpressionSet;
                }
                prec = value;
                if (prec is object)
                {
                    prec.ParametersValueChanged += Accuracy_ParametersValueChanged;
                    prec.ExpressionSet += Accuracy_ExpressionSet;
                }
            }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("DirectedAngle"), TypeConverter(typeof(IntelliAngleConverter)), ReadOnly(true)]
        public double FocusAngle
        {
            get { return ske.RotateAngle; }
            protected set
            {
                ske.RotateAngle = value;
                Pad.Canvas.Invalidate();
            }
        }
        [Browsable(false)]
        public virtual double NewFocusAngle
        {
            get { return FocusAngle; }
        }
        //[Browsable(false)]
        //public PaintableCurve[] Curves
        //{
        //    get { return new PaintableCurve[] { cur }; }
        //}
        //[Browsable(false)]
        //public PaintableCurve[] NewCurves
        //{
        //    get
        //    {
        //        build(newCur, NewLongAxisHalfLength, NewShortAxisHalfLength, NewFocusAngle, NewCenter);
        //        return new PaintableCurve[] { newCur };
        //    }
        //}

        [MultilingualCategory("Parameter"), MultilingualDisplayName("EllipseCenter"), TypeConverter(typeof(IntelliPointConverter))]
        public PointD Center
        {
            get { return ske.Center; }
        }

        [Browsable(false)]
        public PointD PCenter
        {
            get { return pske.Center; }
        }

        [Browsable(false)]
        public virtual PointD NewCenter
        {
            get { return Center; }
        }

        [Browsable(false)]
        public virtual PointD NewPCenter
        {
            get { return PCenter; }
        }
        public override PointD AnchorPoint(PropertyDisplayer disp)
        {
            if (disp == FocusPoint1Displayer)
            {
                return PFocus1;
            }
            if (disp == FocusPoint2Displayer)
            {
                return PFocus2;
            }
            return PCenter;
        }
        [MultilingualCategory(null, "Sketchpad", "Display"), MultilingualDisplayName(null, "FocalHalfLength", "Displayer")]
        public PropertyDisplayer FocalHalfLengthDisplayer
        {
            get { return cDisplayer; }
            set { cDisplayer = value; }
        }
        [MultilingualCategory(null, "Sketchpad", "Display"), MultilingualDisplayName(null, "LongAxisHalfLength", "Displayer")]
        public PropertyDisplayer LongAxisHalfLengthDisplayer
        {
            get { return aDisplayer; }
            set { aDisplayer = value; }
        }
        [MultilingualCategory(null, "Sketchpad", "Display"), MultilingualDisplayName(null, "ShortAxisHalfLength", "Displayer")]
        public PropertyDisplayer ShortAxisHalfLengthDisplayer
        {
            get { return bDisplayer; }
            set { bDisplayer = value; }
        }
        [MultilingualCategory(null, "Sketchpad", "Display"), MultilingualDisplayName("{0}1+{1}", "Focus", "Displayer")]
        public PropertyDisplayer FocusPoint1Displayer
        {
            get { return fp1Displayer; }
            set { fp1Displayer = value; }
        }
        [MultilingualCategory(null, "Sketchpad", "Display"), MultilingualDisplayName("{0}2+{1}", "Focus", "Displayer")]
        public PropertyDisplayer FocusPoint2Displayer
        {
            get { return fp2Displayer; }
            set { fp2Displayer = value; }
        }
        [MultilingualCategory(null, "Sketchpad", "Display"), MultilingualDisplayName(null, "Eccentricity", "Displayer")]
        public PropertyDisplayer EccentricityDisplayer
        {
            get { return eDisplayer; }
            set { eDisplayer = value; }
        }
        [MultilingualCategory(null, "Sketchpad", "Display"), MultilingualDisplayName(null, "EllipseCenter", "Displayer")]
        public PropertyDisplayer CenterDisplayer
        {
            get { return ctDisplayer; }
            set { ctDisplayer = value; }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("FocusDirectrixDistance")]
        public double FocusDirectrixDistance
        {
            get
            {
                return ShortAxisHalfLength * ShortAxisHalfLength / FocalHalfLength;
            }
        }
        [MultilingualCategory(null, "Sketchpad", "Display"), MultilingualDisplayName(null, "FocusDirectrixDistance", "Displayer")]
        public PropertyDisplayer FocusDirectrixDistanceDisplayer
        {
            get { return pDisplayer; }
            set { pDisplayer = value; }
        }
        [Browsable(false)]
        public double NewFocusDirectrixDistance
        {
            get
            {
                return NewShortAxisHalfLength * NewShortAxisHalfLength / NewFocalHalfLength;
            }
        }
        void Accuracy_ParametersValueChanged(DocStringX sender, ParametersValueChangedEventArgs e)
        {
            if (prec.Value > 0)
            {
                step = 1 / prec.Value;
                BuildSamples();
            }
        }
        void Accuracy_ExpressionSet(StringX sender, ExpressionSetEventArgs e)
        {
            if (prec.Value > 0)
            {
                step = 1 / prec.Value;
                BuildSamples();
            }
            else
            {
                Pad.ShowMessage(Resources.JoinLocalizedString(string.Format(Resources.Translate("Of"), Resources.Translate("Ellipse"), Resources.Translate("Accuracy")), Resources.Translate("MustPositive")), MessageType.Error);
                prec.SetExpression(e.OldExpression, false);
            }
        }
        public override void CheckInRegion(RectangleD rect)
        {
            SetInPicker(rect.IntersectCurves(pske.Curves));
            base.CheckInRegion(rect);
        }
        public override void ComponentBuilding(Base component)
        {
            BuildSamples();
            int index = (int)(Math.Round(ShortAxisHalfLength / LongAxisHalfLength, 2) * 100);
            Circumference = index < TofEllipse.Length && index >= 0 ? TofEllipse[index] * (LongAxisHalfLength + ShortAxisHalfLength) : 0;
            Area = Math.PI * LongAxisHalfLength * ShortAxisHalfLength;
            ShowStatus($"{Resources.Translate("Creating")}{Resources.ColonSeparate}{Name}{Resources.LeftParenthesis}{Resources.Translate("EllipseCenter")}{Resources.ColonSeparate}{Pad.ShowPoint(Center)}{Resources.CommaSeparate}{Resources.Translate("LongAxisHalfLength")} = {LongAxisHalfLength}{Resources.CommaSeparate}{Resources.Translate("ShortAxisHalfLength")} = {ShortAxisHalfLength}{Resources.CommaSeparate}{Resources.Translate("FocalHalfLength")} = {FocalHalfLength}{Resources.CommaSeparate}{Resources.Translate("Eccentricity")} = {Eccentricity}");
            base.ComponentBuilding(component);
        }
        protected override string getFormula()
        {
            if (Pad.CoordinateType == CoordinateSystemType.PolarCoordinate)
            {
                return string.Empty;//不会求极坐标方程，暂时留空
            }
            else
            {
                return $"[{Math.Sin(FocusAngle)}(y-{Center.Y})+{Math.Cos(FocusAngle)}(x-{Center.X})]^2/{LongAxisHalfLength * LongAxisHalfLength}+[{Math.Cos(FocusAngle)}(y-{Center.Y})-{Math.Sin(FocusAngle)}(x-{Center.X})]^2/{ShortAxisHalfLength * ShortAxisHalfLength}=1";
            }
        }
        public override void ComponentChanged(ShapeBase component)
        {
            LongAxisHalfLength = NewLongAxisHalfLength;
            ShortAxisHalfLength = NewShortAxisHalfLength;
            ske.Center = NewCenter;
            pske.Center = NewPCenter;
            FocusAngle = NewFocusAngle;
            BuildSamples();
            int index = (int)(Math.Round(ShortAxisHalfLength / LongAxisHalfLength, 2) * 100);
            Circumference = index < TofEllipse.Length && index >= 0 ? TofEllipse[index] * (LongAxisHalfLength + ShortAxisHalfLength) : 0;
            Area = Math.PI * LongAxisHalfLength * ShortAxisHalfLength;
            base.ComponentChanged(component);
        }
        public override void PaintTrack(Graphics gra)
        {
            if (ShowTrack_)
            {
                for (int i = 0; i < track.Count; i++)
                {
                    gra.DrawClosedCurve(TrackPen, track[i]);
                }
            }
            base.PaintTrack(gra);
        }
        public override void RefreshPropertyDisplayersText()
        {
            FocalHalfLengthDisplayer.RefreshText();
            LongAxisHalfLengthDisplayer.RefreshText();
            ShortAxisHalfLengthDisplayer.RefreshText();
            FocusPoint1Displayer.RefreshText();
            FocusPoint2Displayer.RefreshText();
            EccentricityDisplayer.RefreshText();
            CenterDisplayer.RefreshText();
            base.RefreshPropertyDisplayersText();
        }
        public override void RefreshPropertyDisplayersLocation()
        {
            FocalHalfLengthDisplayer.RefreshLocation();
            LongAxisHalfLengthDisplayer.RefreshLocation();
            ShortAxisHalfLengthDisplayer.RefreshLocation();
            FocusPoint1Displayer.RefreshLocation();
            FocusPoint2Displayer.RefreshLocation();
            EccentricityDisplayer.RefreshLocation();
            CenterDisplayer.RefreshLocation();
            base.RefreshPropertyDisplayersLocation();
        }
        public override void PaintProperties(Graphics gra)
        {
            if (ObjectState == ObjectState.Normal && Visible)
            {
                FocalHalfLengthDisplayer.Paint(gra);
                LongAxisHalfLengthDisplayer.Paint(gra);
                ShortAxisHalfLengthDisplayer.Paint(gra);
                FocusPoint1Displayer.Paint(gra);
                FocusPoint2Displayer.Paint(gra);
                EccentricityDisplayer.Paint(gra);
                CenterDisplayer.Paint(gra);
            }
            base.PaintProperties(gra);
        }
        public override void Paint(Graphics gra)
        {
            if (ObjectState == ObjectState.Normal && Visible && IsCreationCompleted)
            {
                Brush bru = FillBrush;
                if (bru != null) pske.Curves[0].Paint(gra, LinePen, bru);
            }
            base.Paint(gra);
        }
        public override void PaintVirtualObjects(Graphics gra)
        {
            if (CanDrawVirtual)
            {
                pske.Curves[0].Paint(gra, Core.Helper.Painter.VirtualLinePen);
            }
            base.PaintVirtualObjects(gra);
        }
        public override void AddTracks()
        {
            track.Add(pske.Curves[0].FSamples);
        }
        public override void ClearTracks()
        {
            track.Clear();
            base.ClearTracks();
        }
        //public override PointD SlideDestination(PointD currentLocation, double length, out bool reverse)
        //{
        //    return ske.SlideDestination(currentLocation, length, out reverse);//使用NewSkeleton可能会降低性能
        //}
        public override void InternalPrepare(PointBase movePoint, ShapeBase sender = null)
        {
            foreach (PointBase item in OutChildren_Point)
            {
                PointD std = (item.ToPointD() - Center).Rotate(-FocusAngle);
                //double angle = 0;
                //switch (std.RCLocation)
                //{
                //    case RectangularCoordinateLocation.Quadrant1:
                //        angle = (Math.Acos(std.X / LongAxisHalfLength) + Math.Asin(std.Y / ShortAxisHalfLength)) / 2;
                //        break;
                //    case RectangularCoordinateLocation.Quadrant2:
                //        angle = Math.Acos(std.X / LongAxisHalfLength);
                //        break;
                //    case RectangularCoordinateLocation.Quadrant3:
                //        angle = 1.5 * Math.PI - (Math.Acos(std.X / LongAxisHalfLength) + Math.Asin(std.Y / ShortAxisHalfLength)) / 2;
                //        break;
                //    case RectangularCoordinateLocation.Quadrant4:
                //        angle = Math.Asin(std.Y / ShortAxisHalfLength);
                //        break;
                //    case RectangularCoordinateLocation.NegativeX:
                //        angle = Math.PI;
                //        break;
                //    case RectangularCoordinateLocation.PositiveY:
                //        angle = Core.Helper.Angle.RightAngle;
                //        break;
                //    case RectangularCoordinateLocation.NegativeY:
                //        angle = Math.PI * 1.5;
                //        break;
                //}
                ControlledOutPointsOriginalInfo.Add(item, new double[] { std.X / LongAxisHalfLength, std.Y / ShortAxisHalfLength });
            }
            base.InternalPrepare(movePoint, sender);
        }
        public override PointD GetOutFreePointRecommendNewLocation(PointBase pt, bool getXY = true)
        {
            PointD xy = NewCenter + new PointD(NewLongAxisHalfLength * ControlledOutPointsOriginalInfo[pt][0], NewShortAxisHalfLength * ControlledOutPointsOriginalInfo[pt][1]).Rotate(NewFocusAngle);
            return getXY ? xy : Pad.XYToPxy(xy);
        }
        public override void InternalClean(PointBase movedPoint, ShapeBase sender = null)
        {
            ControlledOutPointsOriginalInfo.Clear();
            base.InternalClean(movedPoint, sender);
        }
        //public override bool OnObject(PointD pt)
        //{
        //    return (pt.DistanceTo(Focus1) + pt.DistanceTo(Focus2)).AlmostEqual(2 * LongAxisHalfLength);
        //}
        public override PropertyDisplayer[] PropertyDisplayersCheckNearBy(PointD Plocation)
        {
            List<PropertyDisplayer> res = new List<PropertyDisplayer>(base.PropertyDisplayersCheckNearBy(Plocation));
            if (FocalHalfLengthDisplayer.InRegion(Plocation))
            {
                res.Add(FocalHalfLengthDisplayer);
            }
            if (LongAxisHalfLengthDisplayer.InRegion(Plocation))
            {
                res.Add(LongAxisHalfLengthDisplayer);
            }
            if (ShortAxisHalfLengthDisplayer.InRegion(Plocation))
            {
                res.Add(ShortAxisHalfLengthDisplayer);
            }
            if (FocusPoint1Displayer.InRegion(Plocation))
            {
                res.Add(FocusPoint1Displayer);
            }
            if (FocusPoint2Displayer.InRegion(Plocation))
            {
                res.Add(FocusPoint2Displayer);
            }
            if (EccentricityDisplayer.InRegion(Plocation))
            {
                res.Add(EccentricityDisplayer);
            }
            if (CenterDisplayer.InRegion(Plocation))
            {
                res.Add(CenterDisplayer);
            }
            return res.ToArray();
        }
        void build(Curve cur, Curve pCur, double a, double b, double focusAngle, PointD center)
        {
            if (cur == null && pCur == null) return;
            cur?.Clear();
            pCur?.Clear();
            //cur.TangentVectors.Clear();
            //double a2 = a * a, c2 = c * c;
            for (double theta = 0; theta < Core.Helper.Angle.RadRound; theta += step)
            {
                //添加采样点
                //double cos = Math.Cos(theta), rou = Math.Sqrt(a2 * (a2 - c2) / (a2 - c2 * cos * cos));
                //PointD pt = new PointD(rou * cos, rou * Math.Sin(theta)).Rotate(focusAngle) + center;
                PointD pt = new PointD(a * Math.Cos(theta), b * Math.Sin(theta)).Rotate(focusAngle) + center;
                cur?.Add(pt);
                if (pCur != null)
                {
                    if (Pad.Coordinate != null) pt = Pad.Coordinate.XYToPxy(pt);
                    if (pt.IsPaintable) pCur.Add(pt);
                }
                //添加该点处切线方向向量
                //cos = Math.Cos(theta - Curve.DeltaX);
                //rou = Math.Sqrt(a2 * (a2 - c2) / (a2 - c2 * cos * cos));
                //pt = new PointD(rou * cos, rou * Math.Sin(theta - Curve.DeltaX)).Rotate(focusAngle);
                //cos = Math.Cos(theta + Curve.DeltaX);
                //rou = Math.Sqrt(a2 * (a2 - c2) / (a2 - c2 * cos * cos));
                //PointD pt2 = new PointD(rou * cos, rou * Math.Sin(theta + Curve.DeltaX)).Rotate(focusAngle);
                //if (Pad.Coordinate != null)
                //{
                //    pt = Pad.Coordinate.XYToPxy(pt);
                //    pt2 = Pad.Coordinate.XYToPxy(pt2);
                //}
                //cur.TangentVectors.Add(pt2 - pt);
            }
        }
        public void BuildSamples()
        {
            build(ske.Curves[0], pske.Curves[0], LongAxisHalfLength, ShortAxisHalfLength, FocusAngle, Center);
            //cur.Samples.Clear();
            //double c = FocalHalfLength, a2 = LongAxisHalfLength * LongAxisHalfLength, c2 = c * c;
            //for (double theta = 0; theta < Core.Helper.Angle.RadRound; theta += step)
            //{
            //    double cos = Math.Cos(theta), rou = Math.Sqrt((a2 * a2 - a2 * c2) / (a2 - c2 * cos * cos));
            //    PointD pt = new PointD(rou * cos, rou * Math.Sin(theta)).Rotate(FocusAngle) + Center;
            //    if (Pad.Coordinate != null) pt = Pad.Coordinate.XYToPxy(pt);
            //    if (pt.IsPaintable) cur.Samples.Add(pt);
            //}
            FillRegion = Utility.GetSmallestSurroundRect(pske.Curves);
        }
        //public PointD FixOnEllipse(PointD location)
        //{
        //    double theta = Core.Helper.Angle.RadRound - PCenter.GetAngle(location) - RotateAngle,
        //        c = 半焦距长, a2 = a * a, c2 = c * c,
        //        cos = Math.Cos(theta), rou = Math.Sqrt((a2 * a2 - a2 * c2) / (a2 - c2 * cos * cos));
        //    PointD pt = new PointD(rou * cos, rou * Math.Sin(theta)).Rotate(RotateAngle) + Center;
        //    if (Pad.Coordinate != null) pt = Pad.Coordinate.XYToPxy(pt);
        //    return pt;
        //}
        //protected override PointD GetAbsorbedPoint(PointD PLocation, bool getNew = false)
        //{
        //    return PLocation.GetNearestPointFromCurves(getNew ? NewCurves : Curves);
        //}
        public PointD[] GetTangentPoints(PointD passPoint)
        {
            return CurveTangent.GetEllipseTangentPoints(NewCenter, NewLongAxisHalfLength, NewShortAxisHalfLength, NewFocusAngle, passPoint);
        }

        public double? GetTangentLineSlope(PointD pt)
        {
            //if (!OnLine(pt))
            //{
            //    if (Pad.Coordinate != null) pt = Pad.Coordinate.XYToPxy(pt);
            //    pt = pt.GetNearestPointFromCurves(NewCurves);
            //    if (Pad.Coordinate != null) pt = Pad.Coordinate.PxyToXY(pt);
            //}
            return -1 / Math.Tan((pt.GetAngle(NewFocus1) + pt.GetAngle(NewFocus2)) / 2);
        }
        public override void UseFormat(Base obj)
        {
            base.UseFormat(obj);
            if (Settings.Instance.PropertyDisplayerUseFormat)
            {
                ParabolaBase pb = obj as ParabolaBase;
                if (pb != null)
                {
                    FocusPoint1Displayer.UseFormat(pb.FocusPointDisplayer);
                    FocusPoint2Displayer.UseFormat(pb.FocusPointDisplayer);
                }
            }
        }
    }
}
